package demo.QLExpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressLoader;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Description 自定义规则执行工具类
 *
 * @author jiahua.zhang
 * @date 2021/7/16 10:28
 */
public class QlExpressUtil {
    private QlExpressUtil() {
        try {
            registryFunc();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
//        try {
//            runner.addFunctionOfClassMethod("开头是", QlExpressUtil.class.getName(), "checkStartsWith"
//                    , new Class[]{Object.class, String.class}, null);
//            runner.addFunctionOfClassMethod("codeInList", QlExpressUtil.class.getName(), "codeInList",
//                    new Class[] { String.class, List.class }, null);
//            runner.addFunctionOfClassMethod("codeInMap", QlExpressUtil.class.getName(), "codeInMap",
//                    new Class[] { String.class, Map.class }, null);
//            runner.addMacro("基准点数","jzds");
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }

    /**
     * 单例
     */
    private static final QlExpressUtil UTIL = new QlExpressUtil();

    /**
     * 规则执行器
     */
    private final ExpressRunner runner = new ExpressRunner(true,false);

    /**
     * 执行规则
     *
     * @param rule      规则
     * @param parameter 入参
     * @return
     */
    public static Object run(String rule, Map<String, Object> parameter) {
        try {
            return UTIL.runner.execute(rule, parameterTransformationAndReplace(parameter), null, false, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static Object run(String rule, IExpressContext<String, Object> parameter) {
        try {
            return UTIL.runner.execute(rule, parameter, null, false, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void clearMacro(){
        try {
            Field field = ExpressRunner.class.getDeclaredField("loader");
            field.setAccessible(true);
            ExpressLoader loader = (ExpressLoader)field.get(UTIL.runner);
            loader.clear();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 注入runner的方法，勿删
     *
     * @param source
     * @param target
     * @return
     */
    public static boolean checkStartsWith(Object source, String target) {
        if (source instanceof List) {
            for (Object o : (List) source) {
                if (String.valueOf(o).startsWith(target)) {
                    return true;
                }
            }
            return false;
        } else if (source instanceof String) {
            return ((String) source).startsWith(target);
        }
        return false;
    }


    /**
     * 参数转换并且将传入的Map KEY替换为需要转换的KEY
     *
     * @param parameter 用户传入的Map
     * @return 合适规则引擎的类型
     */
    public static IExpressContext<String, Object> parameterTransformationAndReplace(Map<String, Object> parameter) {
        IExpressContext<String, Object> context = new DefaultContext<>();
        parameter.forEach(context::put
        );
        return context;
    }

    public static Boolean codeInList(String code, List<Map<String,String>> codeList){
        for (Map<String, String> map : codeList) {
            if(code.equals(map.get("ITEM_CODE"))){
                return true;
            }
        }
        return false;
    }

    public static Boolean codeInMap(String code, Map<String,String> codeMap){
        if(codeMap.get(code)!=null){
            return true;
        }
        return false;
    }

    /**
     * 注册自定义方法
     *
     * @throws Exception
     */
    private void registryFunc(){
        // contextPutMap方法用于将map中的值放入上下文中
//        runner.addFunction("contextPutAll", new QlContextPutOperator("contextPutAll"));
        Reflections reflections = new Reflections("demo.QLExpress");
        Set<Class<? extends AbstractQLScriptBase>> subType = reflections.getSubTypesOf(AbstractQLScriptBase.class);
        for (Class<? extends AbstractQLScriptBase> aClass : subType) {
            if(aClass.isAnnotation() || aClass.isInterface() || Modifier.isAbstract(aClass.getModifiers())){
                continue;
            }
            AbstractQLScriptBase ts = null;
            try {
                ts = aClass.newInstance();
                runner.addFunction(ts.getFuncName(), ts);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
